/*
 * This file is part of TradeHelper library.
 *
 * TradeHelper library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * TradeHelper library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with TradeHelper library.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.rag.utils;

import com.alee.extended.drag.TextDragHandler;
import com.alee.extended.label.WebLinkLabel;
import com.alee.laf.label.WebLabel;
import com.alee.laf.menu.MenuUtils;
import com.alee.laf.menu.WebMenuItem;
import com.alee.laf.menu.WebPopupMenu;
import com.alee.laf.panel.WebPanel;
import com.alee.laf.separator.WebSeparator;
import com.alee.managers.tooltip.TooltipManager;
import com.alee.managers.tooltip.TooltipWay;
import com.alee.managers.tooltip.WebCustomTooltip;
import com.alee.utils.*;
import com.alee.utils.collection.ValuesTable;
import com.alee.utils.swing.PointProvider;
import com.alee.utils.swing.Timer;
import com.rag.core.*;
import com.rag.forum.ui.*;
import com.rag.managers.ForumManager;
import com.rag.managers.RagManager;
import com.rag.managers.UsersManager;
import com.rag.managers.forum.DataLoadListener;
import info.clearthought.layout.TableLayout;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: mgarin Date: 04.04.12 Time: 16:35
 */

public class RagUtils
{
    private static ImageIcon userIcon =
            new ImageIcon ( RagUtils.class.getResource ( "icons/user.png" ) );
    private static ImageIcon copyIcon =
            new ImageIcon ( RagUtils.class.getResource ( "icons/copy.png" ) );
    private static ImageIcon codeIcon =
            new ImageIcon ( RagUtils.class.getResource ( "icons/code.png" ) );
    private static ImageIcon nameIcon =
            new ImageIcon ( RagUtils.class.getResource ( "icons/name.png" ) );
    private static ImageIcon pmIcon =
            new ImageIcon ( RagUtils.class.getResource ( "icons/pm.png" ) );

    private static Map<String, ImageIcon> iconsCache = new HashMap<String, ImageIcon> ();

    /**
     * Проверяет есть ли в списке объект с данным ID
     */

    public static boolean contains ( List<Item> items, Item item )
    {
        return contains ( items, item.getId () );
    }

    public static boolean contains ( List<Item> items, String itemId )
    {
        for ( Item item : items )
        {
            if ( item.getId ().equals ( itemId ) )
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Копирует итем в клипборд
     */

    public static void copyToClipboard ( Item item )
    {
        try
        {
            Clipboard clipboard = Toolkit.getDefaultToolkit ().getSystemClipboard ();
            clipboard.setContents ( new ItemTransferable ( item.getId () ), null );
        }
        catch ( Throwable ex )
        {
            //
        }
    }

    /**
     * Получает итем из системного клипборда
     */

    public static Item getClipboardItem ()
    {
        Clipboard clipboard = Toolkit.getDefaultToolkit ().getSystemClipboard ();
        return getItem ( clipboard.getContents ( RagUtils.class ) );
    }

    public static Item getItem ( Transferable t )
    {
        try
        {
            String data = ( String ) t.getTransferData ( DataFlavor.stringFlavor );
            if ( data != null )
            {
                // Находим итем по ID
                Item byId = RagManager.getItem ( data );
                if ( byId != null )
                {
                    return byId;
                }

                // todo Распознавать пометки слотов
                // Находим итем по имени
                Item item = findBestItem ( data );
                if ( item != null )
                {
                    return item;
                }

                // Парсим объект итема
                try
                {
                    return ( Item ) XmlUtils.fromXML ( data );
                }
                catch ( Throwable e )
                {
                    return null;
                }
            }
        }
        catch ( Throwable e )
        {
            //
        }
        return null;
    }

    /**
     * Получает топик из Transferable
     */

    public static SingleTopicData getTopicData ( Transferable t )
    {
        try
        {
            String data = ( String ) t.getTransferData ( DataFlavor.stringFlavor );
            if ( data != null )
            {
                // Парсим объект итема
                try
                {
                    return ( SingleTopicData ) XmlUtils.fromXML ( data );
                }
                catch ( Throwable e )
                {
                    //
                }
            }
        }
        catch ( Throwable e )
        {
            //
        }
        return null;
    }

    /**
     * Копирует пользователя в клипборд
     */

    public static void copyToClipboard ( User user )
    {
        try
        {
            Clipboard clipboard = Toolkit.getDefaultToolkit ().getSystemClipboard ();
            clipboard.setContents ( new ItemTransferable ( user.getId () ), null );
        }
        catch ( Throwable ex )
        {
            //
        }
    }

    /**
     * Получает пользователя из системного клипборда
     */

    public static User getClipboardUser ()
    {
        try
        {
            Clipboard clipboard = Toolkit.getDefaultToolkit ().getSystemClipboard ();
            Transferable contents = clipboard.getContents ( RagUtils.class );
            String data = ( String ) contents.getTransferData ( DataFlavor.stringFlavor );
            return data != null ? UsersManager.getUser ( data ) : null;
        }
        catch ( UnsupportedFlavorException e )
        {
            e.printStackTrace ();
        }
        catch ( IOException e )
        {
            e.printStackTrace ();
        }
        return null;
    }

    /**
     * Находит наиболее подходящий итем по имени
     */

    public static Item findBestItem ( String text )
    {
        text = text.toLowerCase ().trim ();
        int max = 0;
        Item item = null;
        for ( Item known : RagManager.getKnownItems ().getValues () )
        {
            if ( known.getId ().equals ( text ) )
            {
                return known;
            }
            for ( String synonym : RagManager.getItemSynonyms ( known ) )
            {
                synonym = synonym.toLowerCase ();
                //                if ( text.contains ( synonym ) )
                //                {
                //                    int length = synonym.length ();
                //                    if ( length > max )
                //                    {
                //                        max = length;
                //                        item = known;
                //                    }
                //                    else if ( length == max )
                //                    {
                //                        item = RagUtils.getMinimumIdItem ( item, known );
                //                    }
                //                }
                //                else
                if ( synonym.contains ( text ) )
                {

                    int length = text.length ();
                    if ( length > max )
                    {
                        max = length;
                        item = known;
                    }
                    else if ( length == max )
                    {
                        item = RagUtils.getMinimumIdItem ( item, known );
                    }
                }
            }
        }
        return item;
    }

    /**
     * Находит все итемы по имени
     */

    public static List<Item> findItems ( String text )
    {
        text = text.toLowerCase ().trim ();
        List<Item> items = new ArrayList<Item> ();
        for ( Item known : RagManager.getKnownItems ().getValues () )
        {
            if ( known.getId ().equals ( text ) )
            {
                items.add ( known );
                break;
            }
            for ( String synonym : RagManager.getItemSynonyms ( known ) )
            {
                synonym = synonym.toLowerCase ();
                //                if ( text.contains ( synonym ) )
                //                {
                //                    items.add ( known );
                //                    break;
                //                }
                //                else
                if ( synonym.contains ( text ) )
                {
                    items.add ( known );
                    break;
                }
            }
        }
        return items;
    }

    /**
     * Создаёт ссылку на копирование ID итема
     */

    public static WebLinkLabel createIdLink ( final Item item )
    {
        return createIdLink ( item.getId () );
    }

    public static WebLinkLabel createIdLink ( final String id )
    {
        final WebLinkLabel idLabel = new WebLinkLabel ( "[ #" + id + " ]" );
        idLabel.setForeground ( Color.BLACK );
        idLabel.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                SystemUtils.copyToClipboard ( id );

                final WebCustomTooltip tooltip = TooltipManager
                        .showOneTimeTooltip ( idLabel, null, "ID итема скопирован", TooltipWay.up );
                new Timer ( 1000, new ActionListener ()
                {
                    public void actionPerformed ( ActionEvent e )
                    {
                        tooltip.closeTooltip ();
                    }
                } ).start ();
            }
        } );
        return idLabel;
    }

    /**
     * Создаёт компонент-таблицу с предоставленными данными
     */

    public static WebPanel createTable ( double firstColumnWidth, int gap,
                                         ValuesTable<JComponent, JComponent> components )
    {
        WebPanel content = new WebPanel ();
        content.setOpaque ( false );

        double[] columns = { firstColumnWidth, TableLayout.PREFERRED, TableLayout.FILL };
        double[] rows = new double[ components.size () * 2 - 1 ];
        for ( int i = 0; i < rows.length; i++ )
        {
            rows[ i ] = TableLayout.PREFERRED;
        }
        TableLayout layout = new TableLayout ( new double[][]{ columns, rows } );
        layout.setHGap ( gap );
        layout.setVGap ( gap );
        content.setLayout ( layout );

        WebSeparator vertical = new WebSeparator ( WebSeparator.VERTICAL );
        content.add ( vertical, "1,0,1," + ( rows.length - 1 ) );

        int row = 0;
        for ( JComponent key : components.getKeys () )
        {
            content.add ( key, "0," + row );
            content.add ( components.get ( key ), "2," + row );
            if ( row < rows.length - 1 )
            {
                WebSeparator horizontal = new WebSeparator ( WebSeparator.HORIZONTAL );
                content.add ( horizontal, "0," + ( row + 1 ) + ",2," + ( row + 1 ) );
            }
            row += 2;
        }

        return content;
    }

    /**
     * Создаёт компонент-ссылку на описание итема
     */

    public static WebLinkLabel createItemInfoLink ( ItemData itemData )
    {
        final Item item = RagManager.getItem ( itemData.getItemId () );
        final WebLinkLabel itemLink = new WebLinkLabel ();

        // Item popup
        itemLink.setLink ( new Runnable ()
        {
            public void run ()
            {
                showItemPopup ( itemLink, item );
            }
        } );

        // Item icon
        itemLink.setIcon ( item.getIcon () );

        // Item text
        itemLink.setText ( getRefineRate ( itemData, item ) + item.getText () );

        // Item text color
        itemLink.setForeground ( Color.BLACK );

        // Drag handler
        itemLink.setTransferHandler ( new TextDragHandler ( itemLink, item.getId () ) );

        setupItemMenu ( itemLink, itemData, item, true );

        return itemLink;
    }

    /**
     * Возвращает текст с заточкой итема
     */

    private static String getRefineRate ( ItemData itemData, Item item )
    {
        Integer refineRate = itemData.getRefineRate ();
        return refineRate != null && refineRate > 0 && RagUtils.canBeRefined ( item ) ?
                "+" + refineRate + " " : "";
    }

    /**
     * Создаёт компонент-ссылку на итем
     */

    public static WebLinkLabel createItemLink ( Item item )
    {
        final WebLinkLabel itemLink = new WebLinkLabel ();
        itemLink.setLink ( item.getRatemyserverLink (), false );
        itemLink.setIcon ( item.getIcon () );
        itemLink.setText ( item.getText () );
        itemLink.setTransferHandler ( new TextDragHandler ( itemLink, item.getId () ) );
        setupItemMenu ( itemLink, null, item, false );
        return itemLink;
    }

    /**
     * Создаёт компонент-ссылку на описание итема
     */

    public static WebLinkLabel createItemInfoLink ( String itemId )
    {
        return createItemInfoLink ( RagManager.getItem ( itemId ) );
    }

    public static WebLinkLabel createItemInfoLink ( final Item item )
    {
        final WebLinkLabel itemLink = new WebLinkLabel ();
        itemLink.setLink ( new Runnable ()
        {
            public void run ()
            {
                showItemPopup ( itemLink, item );
            }
        } );
        itemLink.setIcon ( item.getIcon () );
        itemLink.setText ( item.getText () );
        itemLink.setForeground ( Color.BLACK );
        itemLink.setTransferHandler ( new TextDragHandler ( itemLink, item.getId () ) );
        setupItemMenu ( itemLink, null, item, true );
        return itemLink;
    }

    /**
     * Создаёт попап-меню для ссылки на итем
     */

    public static void setupItemMenu ( final JComponent itemComponent, final ItemData itemData,
                                       final Item item, boolean info )
    {
        WebPopupMenu itemMenu = new WebPopupMenu ();

        if ( info )
        {
            WebMenuItem copy = new WebMenuItem ( "Описание итема", copyIcon );
            copy.addActionListener ( new ActionListener ()
            {
                public void actionPerformed ( ActionEvent e )
                {
                    showItemPopup ( itemComponent, item );
                }
            } );
            itemMenu.add ( copy );
        }
        else
        {
            WebMenuItem copy = new WebMenuItem ( "Просмотреть в базе", copyIcon );
            copy.addActionListener ( new ActionListener ()
            {
                public void actionPerformed ( ActionEvent e )
                {
                    WebUtils.browseSiteSafely ( item.getRatemyserverLink () );
                }
            } );
            itemMenu.add ( copy );
        }

        itemMenu.addSeparator ();

        WebMenuItem copy = new WebMenuItem ( "Копировать", copyIcon );
        copy.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                RagUtils.copyToClipboard ( item );
            }
        } );
        itemMenu.add ( copy );

        if ( itemComponent instanceof ItemPlate )
        {
            final ItemPlate itemPlate = ( ItemPlate ) itemComponent;

            copy.setAccelerator (
                    KeyStroke.getKeyStroke ( KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK ) );

            WebMenuItem cut = new WebMenuItem ( "Вырезать", copyIcon );
            cut.setAccelerator (
                    KeyStroke.getKeyStroke ( KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK ) );
            cut.addActionListener ( new ActionListener ()
            {
                public void actionPerformed ( ActionEvent e )
                {
                    RagUtils.copyToClipboard ( item );
                    itemPlate.deleteItem ();
                }
            } );
            itemMenu.add ( cut );

            WebMenuItem delete = new WebMenuItem ( "Удалить", copyIcon );
            delete.setAccelerator ( KeyStroke.getKeyStroke ( KeyEvent.VK_DELETE, 0 ) );
            delete.addActionListener ( new ActionListener ()
            {
                public void actionPerformed ( ActionEvent e )
                {
                    itemPlate.deleteItem ();
                }
            } );
            itemMenu.add ( delete );

            itemMenu.addSeparator ();
        }

        WebMenuItem name = new WebMenuItem ( "Копировать имя", nameIcon );
        name.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                SystemUtils.copyToClipboard ( item.getTitle () );
            }
        } );
        itemMenu.add ( name );

        WebMenuItem bbcode = new WebMenuItem ( "Копировать BB-code", codeIcon );
        bbcode.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                if ( itemData != null )
                {
                    SystemUtils.copyToClipboard ( RagUtils.getItemDataCode ( itemData, item ) );
                }
                else
                {
                    SystemUtils.copyToClipboard ( RagUtils.getItemCode ( item ) );
                }
            }
        } );
        itemMenu.add ( bbcode );

        itemMenu.addSeparator ();

        WebMenuItem motr = new WebMenuItem ( "Просмотреть в MOTR базе", ServerIcons.motr );
        motr.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                WebUtils.browseSiteSafely ( RagUtils.getMotrLink ( item ) );
            }
        } );
        itemMenu.add ( motr );

        WebMenuItem iro = new WebMenuItem ( "Просмотреть в IroWiki базе", ServerIcons.iro );
        iro.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                WebUtils.browseSiteSafely ( RagUtils.getIroLink ( item ) );
            }
        } );
        itemMenu.add ( iro );

        WebMenuItem rms = new WebMenuItem ( "Просмотреть в RMS базе", ServerIcons.rms );
        rms.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                WebUtils.browseSiteSafely ( item.getRatemyserverLink () );
            }
        } );
        itemMenu.add ( rms );

        MenuUtils.setupPopupMenu ( itemComponent, itemMenu, 2, SwingConstants.RIGHT );
    }

    /**
     * Показывает попап с информацией об итеме в окне компонента
     */

    public static void showItemPopup ( final Component component, final String itemId )
    {
        showItemPopup ( component, RagManager.getItem ( itemId ) );
    }

    public static void showItemPopup ( final Component component, final Item item )
    {
        final Window ancestor = SwingUtils.getWindowAncestor ( component );
        LoaderPopup.showLoader ( ancestor );
        new Thread ( new Runnable ()
        {
            public void run ()
            {
                final ItemPopup itemPopup = new ItemPopup ( item );
                SwingUtils.invokeAndWaitSafely ( new Runnable ()
                {
                    public void run ()
                    {
                        if ( LoaderPopup.isLoaderVisible () )
                        {
                            itemPopup.showPopupAsModal ( ancestor );
                        }
                    }
                } );
            }
        } ).start ();
    }

    /**
     * Создаёт компонент-ссылку на описание итема
     */

    public static WebLinkLabel createTopicInfoLink ( final SingleTopicData topic )
    {
        final WebLinkLabel topicLink = new WebLinkLabel ();
        topicLink.setLink ( new Runnable ()
        {
            public void run ()
            {
                showTopicPopup ( topicLink, topic );
            }
        } );
        topicLink.setIcon ( topic.getIcon () );
        topicLink.setText ( topic.getTopic () );
        topicLink.setForeground ( Color.BLACK );
        topicLink.setHorizontalAlignment ( WebLabel.LEFT );
        topicLink.setVerticalAlignment ( WebLabel.CENTER );
        topicLink.setTransferHandler ( new TextDragHandler ( topicLink )
        {
            public String getText ()
            {
                return XmlUtils.toXML ( topic );
            }
        } );

        WebPopupMenu topicMenu = new WebPopupMenu ();

        WebMenuItem browseTopic = new WebMenuItem ( "Открыть топик в браузере", userIcon );
        browseTopic.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                WebUtils.browseSiteSafely ( topic.getTopicLink () );
            }
        } );
        topicMenu.add ( browseTopic );

        WebMenuItem writeResponse = new WebMenuItem ( "Написать ответ", pmIcon );
        writeResponse.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                WebUtils.browseSiteSafely ( topic.getResponseLink () );
            }
        } );
        topicMenu.add ( writeResponse );

        MenuUtils.setupPopupMenu ( topicLink, topicMenu, new PointProvider ()
        {
            public Point provide ()
            {
                return new Point ( -6, topicLink.getHeight () + 2 );
            }
        } );

        return topicLink;
    }

    /**
     * Показывает попап с информацией о топике
     */

    private static void showTopicPopup ( final Component component, final SingleTopicData topic )
    {
        final Window ancestor = SwingUtils.getWindowAncestor ( component );
        LoaderPopup.showLoader ( ancestor );
        new Thread ( new Runnable ()
        {
            public void run ()
            {
                // Загружаем полностью весь топик
                FullTopicData fullTopicData =
                        ForumManager.loadFullTopicData ( topic, new DataLoadListener ()
                        {
                            public void stateUpdated ( String state, float progress )
                            {
                                LoaderPopup.getInstance ().setText ( state );
                            }
                        } );

                // Показываем попап с топиком
                final TopicPopup topicPopup = new TopicPopup ( fullTopicData );
                SwingUtils.invokeAndWaitSafely ( new Runnable ()
                {
                    public void run ()
                    {
                        if ( LoaderPopup.isLoaderVisible () )
                        {
                            topicPopup.showPopupAsModal ( ancestor, true, true );
                        }
                    }
                } );
            }
        } ).start ();
    }

    /**
     * Создаёт компонент-ссылку на пользователя
     */

    public static WebLinkLabel createUserInfo ( final User user )
    {
        final WebLinkLabel author = new WebLinkLabel ();
        author.setLink ( user.getProfileLink (), false );
        author.setIcon ( userIcon );
        author.setText ( "<html>" + user.getName () + "</html>" );
        author.setHorizontalAlignment ( WebLabel.LEFT );
        author.setVerticalAlignment ( WebLabel.CENTER );

        WebPopupMenu authorMenu = new WebPopupMenu ();

        WebMenuItem profile = new WebMenuItem ( "Просмотреть профиль", userIcon );
        profile.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                WebUtils.browseSiteSafely ( user.getProfileLink () );
            }
        } );
        authorMenu.add ( profile );

        authorMenu.addSeparator ();

        WebMenuItem copy = new WebMenuItem ( "Копировать", copyIcon );
        copy.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                copyToClipboard ( user );
            }
        } );
        authorMenu.add ( copy );

        WebMenuItem copyName = new WebMenuItem ( "Копировать имя", nameIcon );
        copyName.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                SystemUtils.copyToClipboard ( user.getName () );
            }
        } );
        authorMenu.add ( copyName );

        authorMenu.addSeparator ();

        WebMenuItem pm = new WebMenuItem ( "Написать ЛС", pmIcon );
        pm.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                WebUtils.browseSiteSafely ( user.getPmLink () );
            }
        } );
        authorMenu.add ( pm );

        MenuUtils.setupPopupMenu ( author, authorMenu, new PointProvider ()
        {
            public Point provide ()
            {
                return new Point ( -6, author.getHeight () + 2 );
            }
        } );

        return author;
    }

    /**
     * Возвращает итем с ближайшим кол-вом слотов
     */

    public static Item getClosestBySlotItem ( int slotCount, List<Item> items )
    {
        Item minDiffItem = null;
        int minDiff = Integer.MAX_VALUE;
        for ( Item item : items )
        {
            int diff = Math.abs ( getSlotCountSafely ( item ) - slotCount );
            if ( diff < minDiff )
            {
                minDiffItem = item;
                minDiff = Math.abs ( getSlotCountSafely ( item ) - slotCount );
            }
            else if ( diff == minDiff )
            {
                minDiffItem = getMinimumIdItem ( item, minDiffItem );
            }
        }
        return minDiffItem;
    }

    private static int getSlotCountSafely ( Item item )
    {
        return item.getSlotCount () != null ? item.getSlotCount () : 0;
    }

    /**
     * Вовзращает итем с наименьшим ID
     */

    public static Item getMinimumIdItem ( Item item1, Item item2 )
    {
        return Integer.parseInt ( item1.getId () ) < Integer.parseInt ( item2.getId () ) ? item1 :
                item2;
    }

    public static Item getMinimumIdItem ( List<Item> items )
    {
        Item minimumIdItem = null;
        for ( Item item : items )
        {
            if ( minimumIdItem == null )
            {
                minimumIdItem = item;
            }
            else
            {
                minimumIdItem = getMinimumIdItem ( minimumIdItem, item );
            }
        }
        return minimumIdItem;
    }

    /**
     * Является ли итем карточкой
     */

    public static boolean isCard ( String itemId )
    {
        return isCard ( RagManager.getItem ( itemId ) );
    }

    public static boolean isCard ( Item item )
    {
        return item != null && item.getItemType ().equals ( ItemType.card );
    }

    /**
     * Может ли итем быть заточен (не учитывает незатачиваемые по описанию итемы)
     */

    public static boolean canBeRefined ( String itemId )
    {
        return canBeRefined ( RagManager.getItem ( itemId ) );
    }

    public static boolean canBeRefined ( Item item )
    {
        return item != null && ( item.getItemType ().equals ( ItemType.weapon ) ||
                item.getItemType ().equals ( ItemType.armor ) &&
                        !item.getItemClass ().equals ( ItemClass.middle ) &&
                        !item.getItemClass ().equals ( ItemClass.lower ) &&
                        !item.getItemClass ().equals ( ItemClass.accessory ) );
    }

    /**
     * Возвращает стандартный текст для итема
     */

    public static String getItemText ( Item item )
    {
        return item.getTitle () + ( item.getSlotCount () != null && item.getSlotCount () > 0 ?
                " [" + item.getSlotCount () + "]" : "" );
    }

    /**
     * Возвращает 24х24 иконку итема
     */

    public static ImageIcon getItemIcon ( Item item )
    {
        String key = item.getId ();
        if ( iconsCache.containsKey ( key ) )
        {
            return iconsCache.get ( key );
        }
        else
        {
            ImageIcon imageIcon;
            try
            {
                imageIcon = new ImageIcon ( Item.class.getResource (
                        "icons/items/" + ( RagUtils.isCard ( item ) ? "card" : item.getId () ) +
                                ".png" ) );
            }
            catch ( Throwable e )
            {
                imageIcon = getDefaultItemIcon ();

            }
            iconsCache.put ( key, imageIcon );
            return imageIcon;
        }
    }

    private static ImageIcon defaultItemIcon = null;

    private static ImageIcon getDefaultItemIcon ()
    {
        if ( defaultItemIcon == null )
        {
            // Создаём новое изображение
            BufferedImage bi = new BufferedImage ( 24, 24, BufferedImage.TYPE_INT_ARGB );
            Graphics2D g2d = bi.createGraphics ();
            LafUtils.setupAntialias ( g2d );
            g2d.setPaint (
                    new GradientPaint ( 0, 0, Color.WHITE, 24, 24, new Color ( 220, 220, 220 ) ) );
            g2d.fillRoundRect ( 0, 0, 24, 24, 4, 4 );
            g2d.setPaint ( Color.GRAY );
            g2d.drawRoundRect ( 0, 0, 23, 23, 4, 4 );
            g2d.drawLine ( 2, 2, 21, 21 );
            g2d.drawLine ( 21, 2, 2, 21 );
            g2d.dispose ();

            defaultItemIcon = new ImageIcon ( bi );
        }
        return defaultItemIcon;
    }

    /**
     * Возвращает 16x16 иконку итема
     */

    public static ImageIcon getSmallItemIcon ( Item item )
    {
        String key = item.getId () + ".small";
        if ( iconsCache.containsKey ( key ) )
        {
            return iconsCache.get ( key );
        }
        else
        {
            ImageIcon imageIcon = getItemIcon ( item );
            imageIcon = ImageUtils.createPreviewIcon ( imageIcon, 16 );
            iconsCache.put ( key, imageIcon );
            return imageIcon;
        }
    }

    /**
     * Возвращает ID пользователя по ссылке на профиль
     */

    public static String parseUserId ( String profileLink )
    {
        Map<String, List<String>> params = WebUtils.getUrlParameters ( profileLink );
        return params.size () > 0 && params.containsKey ( "u" ) ? params.get ( "u" ).get ( 0 ) :
                TextUtils.generateId ( "USER" );
    }

    /**
     * Возвращает ID топика по ссылке на него
     */

    public static String parseTopicId ( String link )
    {
        Map<String, List<String>> params = WebUtils.getUrlParameters ( link );
        return params.size () > 0 && params.containsKey ( "t" ) ? params.get ( "t" ).get ( 0 ) :
                TextUtils.generateId ( "STD" );
    }

    /**
     * Возвращает ID форума по ссылке на него
     */

    public static String parseForumId ( String link )
    {
        Map<String, List<String>> params = WebUtils.getUrlParameters ( link );
        return params.size () > 0 && params.containsKey ( "f" ) ? params.get ( "f" ).get ( 0 ) :
                TextUtils.generateId ( "STD" );
    }

    /**
     * Возвращают ссылки на разные базы итемов
     */

    public static String getMotrLink ( Item item )
    {
        return getMotrLink ( item.getId (), item.getItemType () );
    }

    public static String getMotrLink ( String id, ItemType itemType )
    {
        if ( itemType.equals ( ItemType.armor ) || itemType.equals ( ItemType.weapon ) )
        {
            return "http://motr-online.com/database/wearables/" + id;
        }
        else if ( itemType.equals ( ItemType.card ) )
        {
            return "http://motr-online.com/database/cards/" + id;
        }
        else
        {
            return "http://motr-online.com/database/items/" + id;
        }
    }

    public static String getIroLink ( Item item )
    {
        return getIroLink ( item.getId () );
    }

    public static String getIroLink ( String id )
    {
        return "http://db.irowiki.org/db/item-info/" + id + "/";
    }

    public static String getRatemyserverLink ( Item item )
    {
        return getRatemyserverLink ( item.getId () );
    }

    public static String getRatemyserverLink ( String id )
    {
        return "http://ratemyserver.net/re_item_db.php?item_id=" + id + "&ird=0&small=1";
    }

    //    public static String fixHtmlText ( String text )
    //    {
    //        return text.replaceAll ( "&apos;", "'" ).replaceAll ( "&nbsp;", " " )
    //                .replaceAll ( "&gt;", ">" ).replaceAll ( "&lt;", "<" ).replaceAll ( "&amp;", "&" );
    //    }

    /**
     * Возвращают изображение итема из МОТР базы
     */

    public static ImageIcon getItemImage ( Item item )
    {
        try
        {
            if ( isCard ( item ) )
            {
                // Картинку карточки возвращаем "как есть"
                return ImageUtils.loadImage (
                        new URL ( "http://85.17.167.159/dbpic/card2/" + item.getId () + ".png" ) );
            }
            else
            {
                // Картинку итема оборачиваем в опрятный бордер
                ImageIcon imageIcon = ImageUtils.loadImage ( new URL (
                        "http://85.17.167.159/dbpic/collection/" + item.getId () + ".png" ) );
                if ( imageIcon != null && imageIcon.getImage () != null )
                {
                    imageIcon.setImage (
                            ImageUtils.createPrettyImage ( imageIcon.getImage (), 0, 4 ) );
                }
                return imageIcon;
            }
        }
        catch ( Throwable e )
        {
            // Не удалось загрузить изображение
            return null;
        }
    }

    /**
     * Возвращают изображение монстра из МОТР базы
     */

    //    public static ImageIcon getMonsterImage ( Monster monster )
    //    {
    //        try
    //        {
    //            return ImageUtils.loadImage ( new URL (
    //                    "http://85.17.167.159/dbpic/monster2/" + monster.getId () + ".png" ) );
    //        }
    //        catch ( MalformedURLException e )
    //        {
    //            return new ImageIcon ();
    //        }
    //    }

    /**
     * Возвращают код итема для МОТР форума
     */

    public static String getItemCode ( Item item )
    {
        // Стандартные варианты:
        // [rocard=id]name[/rocard]
        // [roequip=id]name[/roequip]
        // [roitem=id]name[/roitem]
        // [romonster=id]name[/romonster]

        if ( item.getItemType ().equals ( ItemType.card ) )
        {
            return "[rocard=" + item.getId () + "]" + item.getText () + "[/rocard]";
        }
        else if ( item.getItemType ().equals ( ItemType.weapon ) ||
                item.getItemType ().equals ( ItemType.armor ) ||
                item.getItemType ().equals ( ItemType.ammunition ) ||
                item.getItemType ().equals ( ItemType.throwWeapon ) )
        {
            return "[roequip=" + item.getId () + "]" + item.getText () + "[/roequip]";
        }
        else
        {
            return "[roitem=" + item.getId () + "]" + item.getText () + "[/roitem]";
        }
    }

    public static String getItemDataCode ( ItemData itemData, Item item )
    {
        // Стандартные варианты:
        // [rocard=id]name[/rocard]
        // [roequip=id]name[/roequip]
        // [roitem=id]name[/roitem]
        // [romonster=id]name[/romonster]

        if ( item.getItemType ().equals ( ItemType.card ) )
        {
            return "[rocard=" + item.getId () + "]" + item.getText () + "[/rocard]";
        }
        else if ( item.getItemType ().equals ( ItemType.weapon ) ||
                item.getItemType ().equals ( ItemType.armor ) ||
                item.getItemType ().equals ( ItemType.ammunition ) ||
                item.getItemType ().equals ( ItemType.throwWeapon ) )
        {
            return "[roequip=" + item.getId () + "]" + getRefineRate ( itemData, item ) +
                    item.getText () + "[/roequip]" + getCardsCode ( itemData );
        }
        else
        {
            return "[roitem=" + item.getId () + "]" + item.getText () + "[/roitem]";
        }
    }

    private static String getCardsCode ( ItemData itemData )
    {
        String cardCodes = "";
        List<String> cardIds = itemData.getCardIds ();
        if ( cardIds != null && cardIds.size () > 0 )
        {
            cardCodes += " [";

            List<String> addedIds = new ArrayList<String> ();
            for ( int i = 0; i < cardIds.size (); i++ )
            {
                String id = cardIds.get ( i );

                // Пропускаем повторные карты, они уже были обработаны при первом вхождении
                if ( addedIds.contains ( id ) )
                {
                    continue;
                }

                // Вычисляем количество одинаковых карт с данным ID
                int amount = getCardsAmount ( id, cardIds );
                addedIds.add ( id );

                // Добавляем описание карты
                if ( amount > 1 )
                {
                    // Добавляем кол-во карт данного типа
                    cardCodes += amount + "x";
                }
                cardCodes += getItemCode ( RagManager.getItem ( id ) );

                if ( itemData.getSlotCount () != null &&
                        itemData.getSlotCount () < cardIds.size () &&
                        i < cardIds.size () - 1 && isAnyCardsLeft ( cardIds, addedIds ) )
                {
                    cardCodes += " или ";
                }
            }

            cardCodes += "]";
        }

        return cardCodes;
    }

    public static boolean isAnyCardsLeft ( List<String> cardIds, List<String> addedIds )
    {
        for ( String id : cardIds )
        {
            if ( !addedIds.contains ( id ) )
            {
                return true;
            }
        }
        return false;
    }

    public static int getCardsAmount ( String id, List<String> cardIds )
    {
        int amount = 0;
        for ( String cardId : cardIds )
        {
            if ( cardId.equals ( id ) )
            {
                amount++;
            }
        }
        return amount;
    }
}